//
//  "
//  WiFiMACSim
//
//  Created by Christopher Kemsley on 3/31/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#ifndef WiFiMACSim_Node_hpp
#define WiFiMACSim_Node_hpp

#include <map>
#include <iostream>
#include "Types.hpp"
#include "RunLoop.hpp"
#include "Medium.hpp"
#include "Exception.hpp"
#include "System.hpp"


// Like SlotStamp
#define	NodeStamp	SlotStamp<<" ("<<identity<<") "




SimNamespaceBegin


class	Node : public RunLoopSource
{
public:
	
	typedef	Medium::MsgSet	Msgs ;
	
	
	
	ID const	identity ;
	
	
	
	virtual ~Node () ;
	
	
	
	
protected:
	// Call this
	Node ( ID const & name ) ;
	
	// Override this
	virtual void	update	( UInteger currentTime , Msgs const & currentReception ) = 0 ;
	
	// Use these
	void	markMyMessagesAsFailed	( Msgs const & set ) ;
	
	
private:
	virtual void	runFromRunLoop ( RunLoop & sender , RunLoop::Mode mode ) ;
} ;






template <typename DerivedClass>
class	StateMachineNode : public Node
{
public:
	
	
	/* Types */
	
	typedef	void  (DerivedClass::*UpdateMethod) ( UInteger , Msgs const & ) ;
	
	
	
	/* Initialization */
	
	StateMachineNode ( ID const & name , UInteger startState = 0 ) ;
	
	void	registerStateCallback	( UInteger stateID , UpdateMethod method , std::string const & name ) ;
	
	
	
	/* Queries */
	
	UInteger		state () ;
	virtual void	setState ( UInteger inState ) ;
	
	
	
	
	virtual void	update	( UInteger currentTime , Msgs const & currentReception ) ;
	
	
private:
	UInteger	mState ;
	std::map<UInteger,UpdateMethod>	mCallbacks ;
	std::map<UInteger,std::string>	mNames ;
} ;









template <typename DerivedClass>
class	TransitionalStateMachineNode : public Node
{
public:
	
	
	/* Types */
	
	typedef	void  (DerivedClass::*UpdateMethod) ( Message * message , bool isCompleting , bool lineIsBusy ) ;
	
	
	
	/* Initialization */
	
	TransitionalStateMachineNode ( ID const & name , UInteger startState = 0 ) ;
	
	void	registerStateCallback	( UInteger stateID , UpdateMethod method , std::string const & name ) ;
	
	
	
	/* Queries */
	
	UInteger		state () ;
	virtual void	setState ( UInteger inState ) ;
	
	
	
	
	
	virtual void	update	( UInteger currentTime , Msgs const & currentReception ) ;
	
	
private:
	UInteger		mState ;
	Message*		mRXMessage ;
	enum { kIdle , kOK , kError }	mRXStatus ;
	std::map<UInteger,UpdateMethod>	mCallbacks ;
	std::map<UInteger,std::string>	mNames ;
	
	void	markMyMessagesAsFailed ( Medium::MsgSet const & currentReception ) ;
} ;




#include "Node.hxx"
SimNamespaceEnd
#endif
